package com.monster.security.data.utils;

import com.monster.exception.impl.MonsterRuntimeException;
import com.monster.security.data.common.SecurityExceptionEnum;
import com.monster.security.data.entity.AesKey;
import com.monster.utils.IdUtils;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * Aes加密解密
 *
 * @author kuang
 */
public class AesUtils {
    private AesUtils() {
    }

    /**
     * key的生成方式
     */
    private static final String KEY_ALGORITHM = "AES";
    /**
     * ECB
     */
    private static final String CIPHER_ALGORITHM_ECB = "AES/ECB/PKCS5Padding";
    /**
     * CBC
     */
    private static final String CIPHER_ALGORITHM_CBC = "AES/CBC/PKCS5Padding";

    /**
     * AES 加密操作
     *
     * @param key     加密密码
     * @param content 待加密内容
     * @return 返回Base64转码后的加密数据
     */
    public static String encryptECB(String key, String content) {
        try {
            // 创建密码器
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB);
            // 转换成byte数组
            byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
            // 初始化为加密模式的密码器
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), KEY_ALGORITHM));
            // 加密
            byte[] result = cipher.doFinal(byteContent);
            //通过Base64转码返回
            return Base64.getEncoder().encodeToString(result);
        } catch (NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | BadPaddingException | InvalidKeyException e) {
            throw new MonsterRuntimeException(SecurityExceptionEnum.SECURITY_1000, e);
        }
    }

    /**
     * AES 解密操作
     *
     * @param key     解密的key
     * @param content 需要解密的数据
     * @return 解密后的数据
     */
    public static String decryptECB(String key, String content) {
        try {
            //实例化
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB);
            //使用密钥初始化，设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), KEY_ALGORITHM));
            //执行操作
            byte[] result = cipher.doFinal(Base64.getDecoder().decode(content));
            // 编码返回数据
            return new String(result, "utf-8");
        } catch (NoSuchPaddingException | UnsupportedEncodingException | IllegalBlockSizeException | NoSuchAlgorithmException | BadPaddingException | InvalidKeyException e) {
            throw new MonsterRuntimeException(SecurityExceptionEnum.SECURITY_1001, e);
        }
    }


    /**
     * AES 加密操作
     *
     * @param key     加密密码
     * @param iv      加密向量
     * @param content 待加密内容
     * @return 返回Base64转码后的加密数据
     */
    public static String encryptCBC(String key, String iv, String content) {
        try {
            // 创建密码器
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
            // 转换成byte数组
            byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
            // 初始化为加密模式的密码器
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), KEY_ALGORITHM), new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8)));
            // 加密
            byte[] result = cipher.doFinal(byteContent);
            //通过Base64转码返回
            return Base64.getEncoder().encodeToString(result);
        } catch (NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new MonsterRuntimeException(SecurityExceptionEnum.SECURITY_1000, e);
        }
    }

    /**
     * AES 解密操作
     *
     * @param key     解密的key
     * @param iv      加密向量
     * @param content 需要解密的数据
     * @return 解密后的数据
     */
    public static String decryptCBC(String key, String iv, String content) {
        try {
            //实例化
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_CBC);
            //使用密钥初始化，设置为解密模式
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), KEY_ALGORITHM), new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8)));
            //执行操作
            byte[] result = cipher.doFinal(Base64.getDecoder().decode(content));
            // 编码返回数据
            return new String(result, "utf-8");
        } catch (NoSuchPaddingException | UnsupportedEncodingException | IllegalBlockSizeException | NoSuchAlgorithmException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new MonsterRuntimeException(SecurityExceptionEnum.SECURITY_1001, e);
        }
    }

    /**
     * 生成一对密钥,默认向量模式
     *
     * @return 密钥
     */
    public static AesKey createAesKey() {
        return createAesKey(true);
    }

    /**
     * 生成一对密钥
     *
     * @param isIv 是否向量模式
     * @return 密钥
     */
    public static AesKey createAesKey(boolean isIv) {
        AesKey aesKey = new AesKey();
        String uuid = IdUtils.getUUID();
        if (isIv) {
            String key = uuid.substring(0, 16);
            String iv = uuid.substring(16, 32);
            aesKey.setKey(key);
            aesKey.setIv(iv);
        } else {
            aesKey.setKey(uuid);
        }
        return aesKey;
    }
}
